#include<random>

#include"threadpool.hpp"
#include"log.hpp"

std::random_device rd;
std::mt19937 mt(rd());
std::uniform_int_distribution<int> dist(0,1000);
auto rnd=std::bind(dist,mt);

void func(int slp)
{
    long long tid=tid_to_ll(std::this_thread::get_id());
    DBG("[tid:%lld] hello,func!\n",tid);

    int slp_t=slp+rnd();
    if(slp>0)
    {
        DBG("[tid:%lld]  ======= func sleep %d  =========  \n",tid, slp_t);
        std::this_thread::sleep_for(std::chrono::milliseconds(slp_t));
    }
}

class func_class
{
public:
    func_class(int val):ret_val(val)  
    {}

    int operator()(int n)
    {
        long long tid=tid_to_ll(std::this_thread::get_id());
        DBG("[tid:%lld] hello,func_class! ret value will be %d\n",tid,ret_val);
        return ret_val;
    }
private:
    int ret_val;
};

class func_static
{
public:
    func_static(){}

    static int func_static_int(int n=0)
    {
        long long tid=tid_to_ll(std::this_thread::get_id());
        DBG("[tid:%lld] hello,func_static_int!\n",tid);
        return n;
    }

    static std::string func_static_str(int n,std::string str)
    {
        long long tid=tid_to_ll(std::this_thread::get_id());
        DBG("[tid:%lld] hello,func_static_int!\n",tid);
        return str;
    }
};


int main()
{
    Log::get_instance()->init(nullptr);
    Log::get_instance()->set_log_level(Log::DEBUG_LOG_LEVEL);

    long long tid=tid_to_ll(std::this_thread::get_id());


    Threadpool threadpool(50);

    //普通函数
    auto res_func=threadpool.post_task(func,0);

    //可调用的类对象
    int func_class_ret=100;
    auto res_func_class=threadpool.post_task(func_class{func_class_ret},0);

    //类静态成员函数
    func_static func_sta;
    int func_static_int_ret=999;
    auto res_func_static_int=threadpool.post_task(func_sta.func_static_int,func_static_int_ret);

    std::string func_static_str_ret="multi args";
    auto res_func_static_str=threadpool.post_task(func_sta.func_static_str,rnd(),func_static_str_ret);

    //lambda对象
    auto res_func_lambda=threadpool.post_task([]()->std::string {
                                                                long long tid=tid_to_ll(std::this_thread::get_id());
                                                                DBG("[tid:%lld] hello,lambda_func!\n",tid);
                                                                return "hello, lamda func !";
                                                                });
    
    DBG("[tid:%lld] =======  sleep ========= \n", tid);
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));

    for(int i=0;i<50;i++)
    {
        threadpool.post_task(func,i*100);
    }
    int idle_count=threadpool.get_idle_thread_num();
    DBG("[tid:%lld] =======  post_task all 1 =========  idle_thread_num=%d\n", tid, idle_count);
    DBG("[tid:%lld] =======  sleep ========= \n",tid);
    std::this_thread::sleep_for(std::chrono::seconds(3));

    auto ret_func_class=res_func_class.get();
    auto ret_func_static_int=res_func_static_int.get();
    auto ret_func_static_str=res_func_static_str.get();

    DBG("[tid:%lld] ret_val of func_class: %d\n",tid,ret_func_class);
    DBG("[tid:%lld] ret_val of func_static_int: %d\n",tid,ret_func_static_int);
    DBG("[tid:%lld] ret_val of func_static_str: %s\n",tid,ret_func_static_str);

    DBG("[tid:%lld] =======  sleep ========= \n",tid);
    std::this_thread::sleep_for(std::chrono::seconds(3));
	DBG("[tid:%lld] =======  end ========= \n\n", tid);

    Threadpool pool(4);
    std::vector<std::future<int>> results;

    for(int i=0;i<8;i++)
    {
        results.emplace_back(pool.post_task([i]() ->int {
            long long tid=tid_to_ll(std::this_thread::get_id());
            DBG("[tid:%lld] hello  world %d\n",tid,i);
            std::this_thread::sleep_for(std::chrono::seconds(1));
            return i*i;
        }));
    }

    idle_count=threadpool.get_idle_thread_num();
    DBG("[tid:%lld] =======  post_task all 2 =========  idle_thread_num=%d\n", tid, idle_count);

    for(auto&& result:results)
    {
        DBG("[tid:%lld] get result: %d\n",tid,result.get());
    }

    return 0;
}